package com.jg.xmlSchema2JsonSchema.xsd.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.jg.xmlSchema2JsonSchema.xsd.*;

import java.util.*;


/**
 * Xsd数据读取器
 *
 * @author czg
 */
public class XsdReader {

    private Map<String, XsComplexType> complexTypeMap = null;
    private Map<String, XsSimpleType> simpleTypeMap = null;

    public Map<String, XsComplexType> getComplexTypeMap() {
        return complexTypeMap;
    }

    public void setComplexTypeMap(Map<String, XsComplexType> complexTypeMap) {
        this.complexTypeMap = complexTypeMap;
    }

    public Map<String, XsSimpleType> getSimpleTypeMap() {
        return simpleTypeMap;
    }

    public void setSimpleTypeMap(Map<String, XsSimpleType> simpleTypeMap) {
        this.simpleTypeMap = simpleTypeMap;
    }

    public ChoicesElement getChoices(XsElement element) {
        if ("".equals(element.getType())) {
            return getChoices(element.getComplexType());
        } else {
            String type = element.getType();
            XsComplexType complexType = getPublicComplexType(type);
            return getChoices(complexType);
        }
    }

    public ChoicesElement getChoices(XsComplexType complexType) {
        if (complexType == null) {
            return new ChoicesElement("", (new ArrayList<XsChoice>()).toArray(new XsChoice[0]));
        }
        String name = complexType.getName();
        XsComplexContent complexContent = complexType.getComplexContent();
        if (complexContent == null) {
            XsSequence sequence = complexType.getSequence();
            if (sequence == null) {
                List<XsChoice> elements = complexType.getChoices();
                return new ChoicesElement(name, elements.toArray(new XsChoice[0]));
            }
            List<XsChoice> elements = sequence.getChoices();
            return new ChoicesElement(name, elements.toArray(new XsChoice[0]));
        } else {
            XsExtension extension = complexContent.getExtension();
            if (extension == null) {
                return new ChoicesElement(name, (new ArrayList<XsChoice>()).toArray(new XsChoice[0]));
            } else if ("".equals(extension.getBase())) {
                List<XsChoice> elements = complexType.getSequence().getChoices();
                return new ChoicesElement(name, elements.toArray(new XsChoice[0]));
            } else {
                XsComplexType subComplexType = getPublicComplexType(extension.getBase());
                XsSequence sequence = subComplexType.getSequence();
                if (sequence == null) {
                    return getChoices(subComplexType);
                } else {
                    XsSequence eSequence = extension.getSequence();
                    List<XsChoice> elements;
                    if (eSequence == null) {
                        elements = new ArrayList<>();
                    } else {
                        elements = eSequence.getChoices();
                    }
                    ChoicesElement choicesObject = getChoices(subComplexType);
                    XsChoice[] baseElements = choicesObject.getXsChoices();
                    Collections.addAll(elements, baseElements);
                    return new ChoicesElement(name, elements.toArray(new XsChoice[0]));
                }
            }
        }
    }


    /**
     * 获得给定名称的子XsElement
     *
     * @param element
     * @param name
     * @return
     */
    public XsElement getElement(XsElement element, String name) {
        List<XsElement> elements = getElements(element);
        for (XsElement subElement : elements) {
            if (subElement.getName().equals(name)) {
                return subElement;
            }
        }
        return null;
    }

    public List<XsElement> getElements(XsElement xsElement) {
        if (StrUtil.isEmpty(xsElement.getType())) {
            return getElements(xsElement.getComplexType());
        } else {
            String type = xsElement.getType();
            XsComplexType complexType = getPublicComplexType(type);
            return getElements(complexType);
        }
    }

    /**
     * 获得给定名称的子XsElement
     *
     * @param complexType
     * @param name
     * @return
     * @throws Exception
     */
    public XsElement getElement(XsComplexType complexType, String name) {
        List<XsElement> elements = getElements(complexType);
        for (XsElement subElement : elements) {
            if (subElement.getName().equals(name)) {
                return subElement;
            }
        }
        return null;
    }


    public List<XsElement> getElements(XsComplexType complexType) {
        List<XsElement> elements = new ArrayList<>();
        if (complexType == null) {
            return elements;
        }
        XsComplexContent complexContent = complexType.getComplexContent();
        if (complexContent == null) {
            XsSequence sequence = complexType.getSequence();
            if (sequence == null) {
                XsAll xsAll = complexType.getAll();
                if (ObjectUtil.isNotNull(xsAll)) {
                    elements.addAll(xsAll.getElements());
                }
            } else {
                elements.addAll(sequence.getElements());
            }
            List<XsChoice> choices = complexType.getChoices();
            if (ObjectUtil.isNotNull(choices)) {
                for (XsChoice xsChoice : choices) {
                    elements.addAll(xsChoice.getElements());
                }
            }
        } else {
            XsExtension extension = complexContent.getExtension();
            if (ObjectUtil.isNotNull(extension)) {
                if (StrUtil.isEmpty(extension.getBase())) {
                    elements.addAll(complexType.getSequence().getElements());
                } else {
                    elements.addAll(getExtension(extension));
                }
            }
        }
        return elements;
    }

    private List<XsElement> getExtension(XsExtension extension) {
        XsComplexType subComplexType = getPublicComplexType(extension.getBase());
        List<XsElement> subComplexTypeXsElements = getElements(subComplexType);
        List<XsElement> elements = new ArrayList<>(subComplexTypeXsElements);
        XsSequence xsSequence = extension.getSequence();
        if (xsSequence == null) {
            return elements;
        }
        List<XsElement> extensionElements = xsSequence.getElements();
        elements.addAll(extensionElements);
        return elements;
    }

    public List<XsElement> getExtensionInnerElement(XsElement element) {
        XsExtension xsExtension = element.getExtension();
        if (ObjectUtil.isNotNull(xsExtension)) {
            XsSequence xsSequence = xsExtension.getSequence();
            if (xsSequence == null) {
                return null;
            } else {
                return xsSequence.getElements();
            }
        }
        return null;
    }


    public List<XsAttribute> getAttributes(XsElement element) {
        //获得自己的属性
        List<XsAttribute> mySelfXsAttribute = getAttributes(element.getComplexType());
        if (!StrUtil.isEmpty(element.getType())) {
            XsComplexType complexType = getPublicComplexType(element.getType());
            List<XsAttribute> typeXsAttribute = getAttributes(complexType);
            //合并Type属性
            if (typeXsAttribute != null) {
                mySelfXsAttribute.addAll(typeXsAttribute);
            }
        }
        return mySelfXsAttribute;
    }

    /**
     * 合并属性列表
     *
     * @param sourceList 合并者
     * @param beMerged   被合并者
     * @return
     */
    private List<XsAttribute> mergingAttributesList(List<XsAttribute> sourceList, List<XsAttribute> beMerged) {
        //合并或剔除
        for (XsAttribute xsAttribute : beMerged) {
            for (XsAttribute oldXsAttribute : sourceList) {
                if (oldXsAttribute.getName().equals(xsAttribute.getName())) {
                    sourceList.remove(oldXsAttribute);
                    if ("prohibited".equals(xsAttribute.getUse())) {
                        break;
                    }
                    sourceList.add(xsAttribute);
                    break;
                }
            }
        }
        return sourceList;
    }

    public XsAttribute getAttributes(XsComplexType complexType, String name) {
        List<XsAttribute> xsAttributes = getAttributes(complexType);
        for (XsAttribute xsAttribute : xsAttributes) {
            if (xsAttribute.getName().equals(name)) {
                return xsAttribute;
            }
        }
        return null;
    }

    public List<XsAttribute> getAttributes(XsComplexType complexType) {
        List<XsAttribute> attributesList = new ArrayList<>();
        if (complexType == null) {
            return attributesList;
        }
        attributesList.addAll(complexType.getAttributes());
        XsComplexContent complexContent = complexType.getComplexContent();
        if (complexContent == null) {
            return attributesList;
        } else {
            XsExtension extension = complexContent.getExtension();
            if (extension == null) {
                XsRestriction restriction = complexContent.getRestriction();
                if (restriction == null) {
                    return attributesList;
                } else if ("".equals(restriction.getBase())) {
                    attributesList.addAll(restriction.getAttributes());
                    return attributesList;
                } else {
                    XsComplexType subComplexType = getPublicComplexType(restriction.getBase());
                    List<XsAttribute> complexTypeAttributes = getAttributes(subComplexType);
                    List<XsAttribute> attributes = restriction.getAttributes();
                    List<XsAttribute> tempList = mergingAttributesList(complexTypeAttributes, attributes);
                    return tempList;
                }
            } else if ("".equals(extension.getBase())) {
                attributesList.addAll(extension.getAttributes());
                return attributesList;
            } else {
                attributesList.addAll(extension.getAttributes());
                XsComplexType subComplexType = getPublicComplexType(extension.getBase());
                List<XsAttribute> complexTypeAttributes = getAttributes(subComplexType);
                attributesList.addAll(complexTypeAttributes);
                return attributesList;

            }
        }
    }

    /**
     * 是否存在于已有属性list中
     *
     * @param attributes
     * @param xsAttribute
     * @return
     */
    private boolean isInArrayList(ArrayList<XsAttribute> attributes, XsAttribute xsAttribute) {
        for (XsAttribute attribute : attributes) {
            if (attribute.getName().equals(xsAttribute.getName())) {
                return true;
            }
        }
        return false;
    }

    public XsComplexType getPublicComplexType(String name) {
        if (complexTypeMap == null) {
            return null;
        }
        return complexTypeMap.get(name);
    }

    public XsSimpleType getPublicSimpleType(String name) {
        if (simpleTypeMap == null) {
            return null;
        }
        return simpleTypeMap.get(name);
    }

    public List<XsEnumeration> getEnumerations(String simpleTypeName) {
        XsSimpleType xsSimpleType = getPublicSimpleType(simpleTypeName);
        return xsSimpleType.getRestriction().getEnumerations();
    }

    public XsAttribute getAttribute(XsElement element, String name, boolean isIncludePublicComplexType) {
        List<XsAttribute> xsAttributes = null;
        if ("".equals(element.getType())) {
            xsAttributes = getAttributes(element.getComplexType());
        } else {
            if (isIncludePublicComplexType) {
                XsComplexType complexType = getPublicComplexType(element.getType());
                xsAttributes = getAttributes(complexType);
            }
        }
        for (XsAttribute xsAttribute : xsAttributes) {
            if ("name".equals(xsAttribute.getName())) {
                return xsAttribute;
            }
        }
        return null;
    }


    /**
     * 获得被引用公共的XsComplexType
     *
     * @param xsElement
     * @return
     */
    public XsComplexType getXsComplexTypeOfType(XsElement xsElement) {
        String typeName = getTypeName(xsElement);
        if (StrUtil.isEmpty(typeName)) {
            return null;
        } else {
            return getPublicComplexType(typeName);
        }
    }

    public String getTypeName(XsElement xsElement) {
        if (StrUtil.isEmpty(xsElement.getType())) {
            return getTypeName(xsElement.getComplexType());
        } else {
            return xsElement.getType();
        }
    }

    private String getTypeName(XsComplexType complexType) {
        if (complexType == null) {
            return null;
        }
        XsComplexContent complexContent = complexType.getComplexContent();
        if (complexContent == null) {
            return null;
        } else {
            XsExtension extension = complexContent.getExtension();
            if (extension == null) {
                XsRestriction restriction = complexContent.getRestriction();
                if (restriction == null) {
                    return null;
                } else {
                    if (StrUtil.isEmpty(restriction.getBase())) {
                        return null;
                    } else {
                        return restriction.getBase();
                    }
                }
            } else {
                if (StrUtil.isEmpty(extension.getBase())) {
                    return null;
                } else {
                    return extension.getBase();
                }
            }
        }
    }

}
